home *** CD-ROM | disk | FTP | other *** search
/ Info-Mac 4 / Info_Mac IV CD-ROM (Pacific HiTech Inc.)(August 1994).iso / Development / General / DR1.#1 PowerPlant ƒ / LWindow.cp < prev    next >
Text File  |  1994-02-10  |  39KB  |  1,510 lines

  1. // ===========================================================================
  2. //    LWindow.cp                        ©1993 Metrowerks Inc. All rights reserved.
  3. // ===========================================================================
  4.  
  5. #include "LWindow.h"
  6. #include "LModelProperty.h"
  7. #include "LStream.h"
  8.  
  9. #include "PP_Messages.h"
  10. #include "UAppleEvents.h"
  11. #include "UExtractFromAEDesc.h"
  12. #include "UDesktop.h"
  13. #include "UReanimator.h"
  14. #include "UWindows.h"
  15.  
  16. #include <AERegistry.h>
  17. #include <AEObjects.h>
  18. #include <AEPackObject.h>
  19.  
  20. const DescType    pPosition = 'ppos';
  21.  
  22.  
  23. // ---------------------------------------------------------------------------
  24. //        • LWindow
  25. // ---------------------------------------------------------------------------
  26. //    Default Constructor
  27.  
  28. LWindow::LWindow()
  29. {
  30.     mMacWindowP = nil;
  31.     mStandardSize.width = 32767;
  32.     mStandardSize.height = 32767;
  33.     mMoveOnlyUserZoom = false;
  34.     mAttributes = windAttr_Regular;
  35. }
  36.  
  37.  
  38. // ---------------------------------------------------------------------------
  39. //        • ~LWindow
  40. // ---------------------------------------------------------------------------
  41. //    Destructor
  42.  
  43. LWindow::~LWindow()
  44. {
  45.     if (mMacWindowP != nil) {
  46.                                         // Hide window to ensure proper
  47.                                         //   ordering of remaining windows
  48.         UDesktop::HideDeskWindow(this);
  49.         
  50.             // Delete subpanes *before* disposing of Toolbox WindowRecord.
  51.             // The LView destructor will delete subpanes, but it gets
  52.             // called after this destructor (since LWindow is derived
  53.             // from LView). If we dispose of the Toolbox WindowRecord first,
  54.             // it causes problems for Panes based on other Toolbox data
  55.             // structures, such as standard Controls and TextEdit, that
  56.             // store their own reference to a WindowRecord.
  57.             
  58.         DeleteAllSubPanes();
  59.         
  60.         DisposeWindow(mMacWindowP);        // Kill Toolbox Window
  61.         mMacWindowP = nil;
  62.     }
  63. }
  64.  
  65.  
  66. LWindow*
  67. LWindow::CreateWindow(
  68.     ResIDT        inWindowID,
  69.     LCommander    *inSuperCommander)
  70. {
  71.     SetDefaultCommander(inSuperCommander);
  72.     LWindow    *theWindow =
  73.             (LWindow*) UReanimator::ReadObjects('PObj', inWindowID);
  74.     theWindow->FinishCreate();
  75.     if (theWindow->HasAttribute(windAttr_ShowNew)) {
  76.         theWindow->Show();
  77.     }
  78.     
  79.     return theWindow;
  80. }
  81.  
  82.  
  83. LWindow*
  84. LWindow::CreateWindowStream(
  85.     LStream    *inStream)
  86. {
  87.     DataIDT        dataID;
  88.     inStream->ReadData(&dataID, sizeof(DataIDT));
  89.     SignalIf_(dataID != 'Wind');
  90.     
  91.     return (new LWindow(inStream));
  92. }
  93.  
  94.  
  95. LWindow::LWindow(
  96.     LStream    *inStream)
  97. {
  98.     ResIDT    windResID;
  99.     inStream->ReadData(&windResID, sizeof(ResIDT));
  100.     inStream->ReadData(&mAttributes, sizeof(Uint16));
  101.     
  102.     mStandardSize.width = 32767;
  103.     mStandardSize.height = 32767;
  104.     mMoveOnlyUserZoom = false;
  105.  
  106.     MakeMacWindow(windResID);
  107.     EstablishPort();
  108.     OutOfFocus(nil);
  109.     SetDefaultView(this);
  110. }
  111.  
  112.  
  113. // ---------------------------------------------------------------------------
  114. //        • MakeMacWindow
  115. // ---------------------------------------------------------------------------
  116. //    Make a new Mac Window from a WIND resource template
  117.  
  118. void
  119. LWindow::MakeMacWindow(
  120.     Int16        inWINDid)
  121. {
  122.     SetPaneID(inWINDid);
  123.  
  124.     mMacWindowP = UDesktop::NewDeskWindow(this, inWINDid, window_InFront);
  125.     if (mMacWindowP == nil) {
  126.         Throw_(666);                // ### Error, couldn't make window
  127.     }
  128.     
  129.         // Inside Mac says that an Application may set the windowKind
  130.         // field of a WindowRecord to any value greater than 8 if
  131.         // desired. PowerPlant requires that the windowKind for
  132.         // windows associated with a LWindow object be >= PP_Window_Kind,
  133.         // which is a large constant. For such windows, we PowerPlant
  134.         // stores a pointer to the LWindow object in the refCon.
  135.         // If you wish to use unique kinds for your windows (it's the
  136.         // only way to differentiate LWindow subclasses from just looking
  137.         // at a Toolbox WindowRecord), store the kind number in the
  138.         // refCon field of the WIND resource.
  139.         
  140.                                     // Get WIND resource to check refCon
  141.     SWINDResourceH    theWIND = (SWINDResourceH) GetResource('WIND', inWINDid);
  142.     Int16    kind = (**theWIND).refCon;
  143.     if (kind < PP_Window_Kind) {    // Use value from refCon if it is
  144.         kind = PP_Window_Kind;        //   greater than our special number
  145.     }
  146.     ((WindowPeek) mMacWindowP)->windowKind = kind;
  147.     ReleaseResource((Handle) theWIND);
  148.                                     // Stuff object pointer in refcon
  149.     SetWRefCon(mMacWindowP, (long) this);
  150.     
  151.                                     // Window Frame and Image are the same
  152.                                     //   as its portRect    
  153.     ResizeFrameTo(mMacWindowP->portRect.right - mMacWindowP->portRect.left,
  154.                   mMacWindowP->portRect.bottom - mMacWindowP->portRect.top,
  155.                   false);
  156.     ResizeImageTo(mMacWindowP->portRect.right - mMacWindowP->portRect.left,
  157.                   mMacWindowP->portRect.bottom - mMacWindowP->portRect.top,
  158.                   false);
  159.  
  160.     mMinMaxSize.left = 100;            // ### Hardwired
  161.     mMinMaxSize.top = 100;
  162.  
  163.                                     // Default max Window size to the dimensions
  164.                                     //   of the Gray Region, which is the total
  165.                                     //   Desktop size across all screens
  166.     Rect    grayBox = (**(GetGrayRgn())).rgnBBox;
  167.     mMinMaxSize.right = grayBox.right - grayBox.left;
  168.     mMinMaxSize.bottom = grayBox.bottom - grayBox.top;
  169.     
  170.     CalcRevealedRect();
  171.     CalcPortFrameRect(mUserBounds);
  172.     PortToGlobalPoint(topLeft(mUserBounds));
  173.     PortToGlobalPoint(botRight(mUserBounds));
  174.  
  175. #if 0    // Code above does same thing without direct access to vars
  176.     if (HasAttribute(windAttr_Enabled)) {
  177.         Enable();
  178.     } else {
  179.         Disable();
  180.     }
  181.     Hide();
  182.     Deactivate();
  183. #endif
  184.  
  185.     mVisible = triState_Off;
  186.     mActive = triState_Off;
  187.     mEnabled = triState_Off;
  188.     if (HasAttribute(windAttr_Enabled)) {
  189.         mEnabled = triState_On;
  190.     }
  191. }
  192.  
  193.  
  194. // ---------------------------------------------------------------------------
  195. //        • FetchWindowObject
  196. // ---------------------------------------------------------------------------
  197. //    Return the PowerPlant Window object associated with a Mac WindowPtr
  198. //
  199. //    Returns nil if the WindowPtr is not a PowerPlant Window
  200.  
  201. LWindow*
  202. LWindow::FetchWindowObject(
  203.     WindowPtr    inWindowP)
  204. {
  205.     LWindow    *ppWindow = nil;
  206.                                     // PowerPlant Windows have a special
  207.                                     // windowKind
  208.     if ( (inWindowP != nil)  &&
  209.          (((WindowPeek) inWindowP)->windowKind >= PP_Window_Kind) ) {
  210.                                     // Object pointer is in the refCon
  211.             ppWindow = (LWindow*) GetWRefCon(inWindowP);
  212.     }
  213.     
  214.     return ppWindow;
  215. }
  216.  
  217.  
  218. GrafPtr
  219. LWindow::GetMacPort() const
  220. {
  221.     return mMacWindowP;
  222. }
  223.  
  224.  
  225. // ---------------------------------------------------------------------------
  226. //        • HasAttribute
  227. // ---------------------------------------------------------------------------
  228. //    Return whether a Window has the specified attribute
  229.  
  230. Boolean
  231. LWindow::HasAttribute(
  232.     EWindAttr    inAttribute) const
  233. {
  234.     return ((mAttributes & inAttribute) != 0);
  235. }
  236.  
  237.  
  238. void
  239. LWindow::GetMinMaxSize(
  240.     Rect    &outRect) const
  241. {
  242.     outRect = mMinMaxSize;
  243. }
  244.  
  245.  
  246. void
  247. LWindow::SetMinMaxSize(
  248.     const Rect    &inRect)
  249. {
  250.     mMinMaxSize = inRect;
  251. }
  252.  
  253.  
  254. void
  255. LWindow::GetStandardSize(
  256.     SDimension16    &outStdSize)
  257. {
  258.     outStdSize = mStandardSize;
  259. }
  260.  
  261.  
  262. void
  263. LWindow::SetStandardSize(
  264.     SDimension16    inStdSize)
  265. {
  266.     mStandardSize = inStdSize;
  267. }
  268.  
  269.  
  270. StringPtr
  271. LWindow::GetDescriptor(
  272.     Str255    outDescriptor) const
  273. {
  274.     GetWTitle(mMacWindowP, outDescriptor);
  275.     return outDescriptor;
  276. }
  277.  
  278.  
  279. void
  280. LWindow::SetDescriptor(
  281.     ConstStr255Param    inDescriptor)
  282. {
  283.     SetWTitle(mMacWindowP, inDescriptor);
  284. }
  285.  
  286.  
  287. // ---------------------------------------------------------------------------
  288. //        • HandleClick
  289. // ---------------------------------------------------------------------------
  290. //    Respond to a click on a Window
  291. //
  292. //    The inPart parameter is the part code returned by the Toolbox FindWindow
  293. //    routine.
  294.  
  295. void
  296. LWindow::HandleClick(
  297.     const EventRecord&    inMacEvent,
  298.     Int16                inPart)
  299. {
  300.     switch (inPart) {
  301.     
  302.         case click_OutsideModal:    // Special case for clicking outside
  303.             SysBeep(1);                //   a modal window
  304.             break;
  305.     
  306.         case inContent:
  307.             ClickInContent(inMacEvent);
  308.             break;
  309.             
  310.         case inDrag:
  311.             ClickInDrag(inMacEvent);
  312.             break;
  313.             
  314.         case inGrow:
  315.             ClickInGrow(inMacEvent);
  316.             break;
  317.             
  318.         case inGoAway:
  319.             ClickInGoAway(inMacEvent);
  320.             break;
  321.             
  322.         case inZoomIn:
  323.         case inZoomOut:
  324.             ClickInZoom(inMacEvent, inPart);
  325.             break;
  326.     }
  327. }
  328.  
  329.  
  330. // ---------------------------------------------------------------------------
  331. //        • ClickInContent
  332. // ---------------------------------------------------------------------------
  333. //    Respond to a click in the content region of a Window
  334.  
  335. void
  336. LWindow::ClickInContent(
  337.     const EventRecord&    inMacEvent)
  338. {
  339.                                     // Enabled Windows respond to clicks
  340.     Boolean        respondToClick = HasAttribute(windAttr_Enabled);
  341.     
  342.                                     // Set up our extended event record
  343.     SMouseDownEvent        theMouseDown;
  344.     theMouseDown.wherePort = inMacEvent.where;
  345.     GlobalToPortPoint(theMouseDown.wherePort);
  346.     theMouseDown.whereLocal = theMouseDown.wherePort;
  347.     theMouseDown.macEvent = inMacEvent;
  348.     theMouseDown.delaySelect = false;
  349.     
  350.     if (!UDesktop::WindowIsSelected(this)) {
  351.                                     // Window is not in front, we might
  352.                                     //   need to select it
  353.         Boolean    doSelect = true;
  354.         if (HasAttribute(windAttr_DelaySelect)) {
  355.                                     // Delay selection until after handling
  356.                                     //   the click (called click-through)
  357.             theMouseDown.delaySelect = true;
  358.             Click(theMouseDown);
  359.             
  360.                                     // After click-through, we select the
  361.                                     //   Window if the mouse is still down
  362.                                     //   or the mouse up occurred inside
  363.                                     //   this Window.
  364.             EventRecord    mouseUpEvent;
  365.             if (!StillDown() && GetOSEvent(mUpMask, &mouseUpEvent)) {
  366.                                     // Check location of mouse up event
  367.                 WindowPtr    upWindow;
  368.                 FindWindow(mouseUpEvent.where, &upWindow);
  369.                 doSelect = (upWindow == mMacWindowP);
  370.             }
  371.         }
  372.         
  373.         if (doSelect) {                // Selecting a Window brings it to the
  374.                                     //   front of its layer and activates it
  375.             UDesktop::SelectDeskWindow(this);
  376.             respondToClick = HasAttribute(windAttr_GetSelectClick);
  377.         }
  378.     }
  379.     
  380.     if (respondToClick && !theMouseDown.delaySelect) {
  381.         theMouseDown.delaySelect = false;
  382.         Click(theMouseDown);
  383.     }
  384. }
  385.  
  386.  
  387. // ---------------------------------------------------------------------------
  388. //        • ClickInDrag
  389. // ---------------------------------------------------------------------------
  390. //    Handle click in drag region of a Window
  391.  
  392. void
  393. LWindow::ClickInDrag(
  394.     const EventRecord&    inMacEvent)
  395. {
  396.                                         // Save old bounds (content region
  397.                                         //    is in global coords)
  398.     Rect    bounds = (*((WindowPeek)mMacWindowP)->contRgn)->rgnBBox;
  399.     
  400.     Rect    dragRect = (**(GetGrayRgn())).rgnBBox;
  401.     InsetRect(&dragRect, 4, 4);
  402.     UDesktop::DragDeskWindow(this, inMacEvent, dragRect);
  403.     
  404.         // DragWindow will move the window. However, send AppleEvent to
  405.         // set the bounds (but don't execute it), so that Script engines
  406.         // can record the action.
  407.     
  408.                                         // Compare old and new bounds
  409.     if (!EqualRect(&bounds,
  410.                     &(*((WindowPeek)mMacWindowP)->contRgn)->rgnBBox)) {
  411.                     
  412.                                         // Send but don't execute
  413.                                         //   SetBounds AppleEvent
  414.         SendAESetPosition
  415.             (topLeft((*((WindowPeek)mMacWindowP)->contRgn)->rgnBBox),
  416.                         false);
  417.                         
  418.         Point    offset = {0, 0};        // Dragging window offsets the
  419.         PortToGlobalPoint(offset);        //   position of the UserBounds
  420.         offset.h -= mUserBounds.left;    //   for zooming
  421.         offset.v -= mUserBounds.top;
  422.         OffsetRect(&mUserBounds, offset.h, offset.v);
  423.         mMoveOnlyUserZoom = false;
  424.     }
  425. }
  426.  
  427.  
  428. // ---------------------------------------------------------------------------
  429. //        • ClickInGrow
  430. // ---------------------------------------------------------------------------
  431.  
  432. void
  433. LWindow::ClickInGrow(
  434.     const EventRecord&    inMacEvent)
  435. {
  436.     long        newSize;                // New width and height for window
  437.     Rect        theRect;                // Utility rectangle
  438.     
  439.     theRect = mMinMaxSize;                // Store instance variable in local
  440.                                         //   var in case memory moves
  441.                                         
  442.     theRect.right += 1;                    // GrowWindow trap is off by one
  443.     theRect.bottom += 1;                //   when growing window to its max
  444.                                         //   size. Mostly likely caused by
  445.                                         //   using the PinRect trap.
  446.                     
  447.                                             // Let Toolbox draw the grow image
  448.                                             //   newSize has the new height in
  449.                                             //   the hi word, width in lo word
  450.     newSize = GrowWindow(mMacWindowP, inMacEvent.where, &theRect);
  451.     
  452.     if (newSize != 0) {                    // If window size changed ...
  453.                                         // Get current bounds (global coords)
  454.         theRect = (*((WindowPeek)mMacWindowP)->contRgn)->rgnBBox;
  455.                                         // Compute new bounds (global coords)
  456.         theRect.right = theRect.left + LoWord(newSize);
  457.         theRect.bottom = theRect.top + HiWord(newSize);
  458.                                         // Change the window size
  459.         SendAESetBounds(&theRect, true);
  460.     }
  461. }
  462.  
  463.  
  464. // ---------------------------------------------------------------------------
  465. //        • ClickInGoAway
  466. // ---------------------------------------------------------------------------
  467. //    Handle a click inside the close box of a Window
  468.  
  469. void
  470. LWindow::ClickInGoAway(
  471.     const EventRecord&    inMacEvent)
  472. {
  473.     if (TrackGoAway(mMacWindowP, inMacEvent.where)) {
  474.         SendAEClose();
  475.     }
  476. }
  477.  
  478.  
  479. // ---------------------------------------------------------------------------
  480. //        • ClickInZoom
  481. // ---------------------------------------------------------------------------
  482. //    Handle a click inside the zoom box of a Window
  483.  
  484. void
  485. LWindow::ClickInZoom(
  486.     const EventRecord&    inMacEvent,
  487.     short                inZoomDirection)
  488. {
  489.     if (TrackBox(mMacWindowP, inMacEvent.where, inZoomDirection)) {
  490.         SendAESetZoom();
  491.     }
  492. }
  493.  
  494.  
  495. // ---------------------------------------------------------------------------
  496. //        • UpdatePort
  497. // ---------------------------------------------------------------------------
  498. //    Redraw invalidated area of the Window
  499. //
  500. //    The Mac WindowPtr maintains an update region that defines the area
  501. //    that needs to be redrawn.
  502.  
  503. void
  504. LWindow::UpdatePort()
  505. {
  506.     GrafPtr        originalPort;
  507.     GetPort(&originalPort);
  508.     
  509.     SetPort(mMacWindowP);
  510.     SetOrigin(0,0);
  511.     OutOfFocus(nil);
  512.     
  513.     BeginUpdate(mMacWindowP);
  514.     
  515.     Draw(mMacWindowP->visRgn);
  516.     
  517.     EndUpdate(mMacWindowP);
  518.     
  519.     SetPort(originalPort);
  520.     OutOfFocus(nil);
  521. }
  522.  
  523.  
  524. // ---------------------------------------------------------------------------
  525. //        • EstablishPort
  526. // ---------------------------------------------------------------------------
  527. //    Make Window the current Port
  528.  
  529. void
  530. LWindow::EstablishPort()
  531. {
  532.     if ((mMacWindowP != nil) && (qd.thePort != mMacWindowP)) {
  533.         SetPort(mMacWindowP);
  534.     }
  535. }
  536.  
  537.  
  538. void
  539. LWindow::InvalPortRect(
  540.     const Rect    *inRect)
  541. {
  542.     FocusDraw();
  543.     ::InvalRect(inRect);
  544. }
  545.  
  546.  
  547. void
  548. LWindow::InvalPortRgn(
  549.     RgnHandle    inRgnH)
  550. {
  551.     FocusDraw();
  552.     ::InvalRgn(inRgnH);
  553. }
  554.  
  555.  
  556. void
  557. LWindow::ValidPortRect(
  558.     const Rect    *inRect)
  559. {
  560.     FocusDraw();
  561.     ::ValidRect(inRect);
  562. }
  563.  
  564.  
  565. void
  566. LWindow::ValidPortRgn(
  567.     RgnHandle    inRgnH)
  568. {
  569.     FocusDraw();
  570.     ::ValidRgn(inRgnH);
  571. }
  572.  
  573.  
  574. void
  575. LWindow::Select()
  576. {
  577.     UDesktop::SelectDeskWindow(this);
  578. }
  579.  
  580.  
  581. void
  582. LWindow::Show()
  583. {
  584.     if (mVisible == triState_Off) {
  585.         mVisible = triState_On;
  586.         ShowSelf();
  587.         LView::Show();
  588.     }
  589. }
  590.  
  591.  
  592. void
  593. LWindow::ShowSelf()
  594. {
  595.     UDesktop::ShowDeskWindow(this);
  596. }
  597.  
  598.  
  599. void
  600. LWindow::HideSelf()
  601. {
  602.     UDesktop::HideDeskWindow(this);
  603. }
  604.  
  605.  
  606. void
  607. LWindow::Activate()
  608. {
  609.     if (mActive == triState_Off) {
  610.         mActive = triState_On;
  611.         ActivateSelf();
  612.         LView::Activate();
  613.         
  614.             // Normally the active Window contains the Target. If this
  615.             // Window can be the Target, restore the Target to what
  616.             // it was when the Window was last active. Don't do this
  617.             // if the Window is already on duty (which happens when
  618.             // the Window is a Superior of a Window that was just
  619.             // deactivated).
  620.             
  621.         if (HasAttribute(windAttr_Targetable) && !IsOnDuty()) {
  622.             RestoreTarget();
  623.         }
  624.     }
  625. }
  626.  
  627.  
  628. void
  629. LWindow::ActivateSelf()
  630. {
  631.     HiliteWindow(mMacWindowP, true);
  632.     DrawSizeBox();
  633. }
  634.  
  635.  
  636. void
  637. LWindow::Deactivate()
  638. {
  639.     LView::Deactivate();
  640.     
  641.     if (IsOnDuty()) {
  642.     
  643.         // Switch target to SuperCommander to prevent an
  644.         // inactive Window from containing the Target
  645.         
  646.         SwitchTarget(GetSuperCommander());
  647.     }
  648. }
  649.  
  650.  
  651. void
  652. LWindow::DeactivateSelf()
  653. {
  654.     HiliteWindow(mMacWindowP, false);
  655.     DrawSizeBox();
  656. }
  657.  
  658.  
  659. void
  660. LWindow::Enable()
  661. {
  662.     if (mEnabled == triState_Off) {
  663.         mEnabled = triState_On;
  664.         EnableSelf();
  665.         LView::Enable();
  666.     }
  667. }
  668.  
  669.  
  670. void
  671. LWindow::Suspend()
  672. {
  673.     if (HasAttribute(windAttr_HideOnSuspend)) {
  674.         SuperHide();
  675.     } else if (IsActive()) {
  676.         Deactivate();
  677.     }
  678. }
  679.  
  680.  
  681. void
  682. LWindow::Resume()
  683. {
  684.     if (HasAttribute(windAttr_HideOnSuspend)) {
  685.         HiliteWindow(mMacWindowP, true);
  686.         SuperShow();
  687.     }
  688. }
  689.  
  690.  
  691. void
  692. LWindow::DrawSelf()
  693. {
  694. //    PaintRect(&mMacWindowP->portRect);        // DEBUG, for checking update region
  695.  
  696.     if (HasAttribute(windAttr_EraseOnUpdate)) {
  697.         EraseRect(&mMacWindowP->portRect);
  698.     }
  699.     
  700.     DrawSizeBox();
  701. }
  702.  
  703.  
  704. // ---------------------------------------------------------------------------
  705. //        • DrawSizeBox
  706. // ---------------------------------------------------------------------------
  707. //    Draw standard size box for resizable Windows
  708.  
  709. void
  710. LWindow::DrawSizeBox()
  711. {
  712.     if (HasAttribute(windAttr_SizeBox)) {
  713.     
  714.             // The Toolbox trap DrawGrowIcon draws the size box in
  715.             // the lower right corner of a Window, but it also outlines
  716.             // the typical scroll bar areas at the right and bottom of
  717.             // a Window. We want this routine to work for Windows that
  718.             // don't necessarily have standard scroll bars, so we
  719.             // temporarily change the clipping region to draw just the
  720.             // size box.
  721.     
  722.         FocusDraw();
  723.         RgnHandle    saveClip = NewRgn();
  724.         GetClip(saveClip);
  725.         
  726.         Rect    sizeBox = mMacWindowP->portRect;
  727.         sizeBox.left = sizeBox.right - 15;
  728.         sizeBox.top = sizeBox.bottom - 15;
  729.         ClipRect(&sizeBox);
  730.         
  731.         DrawGrowIcon(mMacWindowP);
  732.         
  733.         SetClip(saveClip);
  734.         DisposeRgn(saveClip);
  735.     }
  736. }
  737.  
  738.  
  739. static Boolean                    // ### put in a utility class
  740. IsColorGrafPort(
  741.     GrafPtr    inMacPortP)
  742. {
  743.                                 // Highest 2 bits of rowBytes are
  744.                                 //   set for a Color GrafPort
  745.     return ((inMacPortP->portBits.rowBytes & 0xC000) == 0xC000);
  746. }
  747.  
  748.  
  749. // ---------------------------------------------------------------------------
  750. //        • GlobalToPortPoint
  751. // ---------------------------------------------------------------------------
  752. //    Convert a point from global (screen) coordinates to a Window's Port
  753. //    coordinates
  754.  
  755. void
  756. LWindow::GlobalToPortPoint(
  757.     Point    &ioPoint) const
  758. {
  759.         // Windows have a reference to the pixel image of the main screen--
  760.         // portBits for B&W and portPixMap for color windows. The bounds
  761.         // of the pixel image specify the alignment of the *local* Window
  762.         // coordinates with *global* coordinates:
  763.         //        localPt = globalPt + topLeft(imageBounds)
  764.         //
  765.         // To convert from *local* to *port* coordinates, we offset by
  766.         // the top left of the Window's port rectangle:
  767.         //        portPt = localPt - topLeft(portRect)
  768.         //
  769.         // Therefore,
  770.         //        portPt = globalPt + topLeft(imageBounds) - topLeft(portRect)
  771.         //
  772.         // Note: We don't use the Toolbox routine GlobalToLocal because
  773.         // that routine depends on the current port and the current port
  774.         // origin. To use GlobalToLocal we would have to do the following:
  775.         //        GrafPtr savePort;
  776.         //        GetPort(&savePort);
  777.         //        Point    saveOrigin = topLeft(mMacWindowP->portRect);
  778.         //        SetPort(mMacWindowP);
  779.         //        SetOrigin(0,0);
  780.         //        GlobalToLocal(ioPoint);
  781.         //        SetOrigin(saveOrigin.h, saveOrigin.v);
  782.         //        SetPort(savePort);
  783.         // The equation above avoids all this saving/setting/restoring
  784.         // of the current port and port origin.
  785.  
  786.                                     // Assume a B&W Window
  787.     Point    localOffset = topLeft(mMacWindowP->portBits.bounds);
  788.     if (IsColorGrafPort(mMacWindowP)) {
  789.                                     // Nope, it's a color Window
  790.         CGrafPtr    colorPortP = (CGrafPtr) mMacWindowP;
  791.         localOffset = topLeft((**(colorPortP->portPixMap)).bounds);
  792.         
  793.     }
  794.     
  795.     ioPoint.h += (localOffset.h - mMacWindowP->portRect.left);
  796.     ioPoint.v += (localOffset.v - mMacWindowP->portRect.top);
  797. }
  798.  
  799.  
  800. // ---------------------------------------------------------------------------
  801. //        • PortToGlobalPoint
  802. // ---------------------------------------------------------------------------
  803. //    Convert a point from Port to Global (screen) coordinates
  804. //        [see discussion above for GlobalToPortPoint() for comments]
  805.  
  806. void
  807. LWindow::PortToGlobalPoint(
  808.     Point    &ioPoint) const
  809. {
  810.                                     // Assume a B&W Window
  811.     Point    localOffset = topLeft(mMacWindowP->portBits.bounds);
  812.     if (IsColorGrafPort(mMacWindowP)) {
  813.                                     // Nope, it's a color Window
  814.         CGrafPtr    colorPortP = (CGrafPtr) mMacWindowP;
  815.         localOffset = topLeft((**(colorPortP->portPixMap)).bounds);
  816.         
  817.     }
  818.     
  819.     ioPoint.h -= (localOffset.h - mMacWindowP->portRect.left);
  820.     ioPoint.v -= (localOffset.v - mMacWindowP->portRect.top);
  821. }
  822.  
  823.  
  824. // ===========================================================================
  825. // • Sending Apple Events                                Sending Apple Events •
  826. // ===========================================================================
  827.  
  828. // ---------------------------------------------------------------------------
  829. //        • SendAESetPosition
  830. // ---------------------------------------------------------------------------
  831. //    AppleEvent for moving a Window to a new position
  832. //
  833. //    inPosition is the location for the top left corner of the Window's
  834. //        port rectangle, in Global coordinates
  835. //    Set inExecuteAE to true to actually move the Window, false to
  836. //    just send the event for script recording purposes. You'll use the
  837. //    false value when you have already moved the window in response to
  838. //    tracking user actions (the Toolbox trap DragWindow move the Window).
  839.  
  840. void
  841. LWindow::SendAESetPosition(
  842.     Point    inPosition,
  843.     Boolean    inExecuteAE)
  844. {
  845.     Try_
  846.     LModelProperty*    positionProperty = new LModelProperty(pPosition, this);
  847.     positionProperty->SendSetDataAE(typeQDPoint, (Ptr) &inPosition,
  848.                                         sizeof(Point), inExecuteAE);
  849.     delete positionProperty;
  850. }
  851.  
  852.  
  853. // ---------------------------------------------------------------------------
  854. //        • SendAESetBounds
  855. // ---------------------------------------------------------------------------
  856. //    AppleEvent for changing the size of a Window
  857. //
  858. //    inBounds is the new port rectangle for the Window, in Global coordinates.
  859. //    Set inExecuteAE to true to actually resize the Window, false to
  860. //    just send the event for script recording purposes.
  861.  
  862. void
  863. LWindow::SendAESetBounds(
  864.     Rect    *inBounds,                    // New bounds in global coords
  865.     Boolean    inExecuteAE)
  866. {
  867.     Try_
  868.     LModelProperty*    positionProperty = new LModelProperty(pBounds, this);
  869.     positionProperty->SendSetDataAE(typeQDRectangle, (Ptr) inBounds,
  870.                                         sizeof(Rect), inExecuteAE);
  871.     delete positionProperty;
  872. }
  873.  
  874.  
  875. // ---------------------------------------------------------------------------
  876. //        • SendAESetZoom
  877. // ---------------------------------------------------------------------------
  878. //    AppleEvent for zooming a Window
  879. //
  880. //    This function figures out whether to zoom in or out based on the
  881. //    current window size and location
  882.  
  883. void
  884. LWindow::SendAESetZoom()
  885. {
  886.                                         // Determine zoom direction
  887.     Rect    stdBounds;
  888.     Boolean    zoomToStdState = !CalcStandardBounds(stdBounds);
  889.  
  890.     Try_
  891.     LModelProperty*    zoomProperty = new LModelProperty(pIsZoomed, this);
  892.     zoomProperty->SendSetDataAE(typeBoolean, (Ptr) &zoomToStdState,
  893.                                         sizeof(Boolean), true);
  894.     delete zoomProperty;
  895. }
  896.  
  897.  
  898. // ---------------------------------------------------------------------------
  899. //        • SendAEClose
  900. // ---------------------------------------------------------------------------
  901. //    AppleEvent for closing a Window
  902.  
  903. void
  904. LWindow::SendAEClose()
  905. {
  906.     Try_
  907.     AppleEvent    theAppleEvent;
  908.     UAppleEvents::MakeAppleEvent(kAECoreSuite, kAEClose, theAppleEvent);
  909.     CheckThrow_
  910.  
  911.     StAEDescriptor    windowSpec;
  912.     MakeSpecifier(windowSpec.mDesc);
  913.     CheckThrow_
  914.     OSErr err = AEPutParamDesc(&theAppleEvent, keyDirectObject,
  915.                                 &windowSpec.mDesc);
  916.     if (err != noErr) Throw_(err);
  917.  
  918.     UAppleEvents::SendAppleEvent(theAppleEvent, true);
  919. }
  920.  
  921.  
  922. // ===========================================================================
  923. // • Responding To Apple Events                      Responding To Apple Events •
  924. // ===========================================================================
  925.  
  926. OSErr
  927. LWindow::DoAEClose()
  928. {
  929.     if ( (GetSuperCommander() == nil) ||
  930.          GetSuperCommander()->AllowSubRemoval(this) ) {
  931.                                  // Set flag to delete Window after completion
  932.                                  //   of the Close AppleEvent
  933.         DeleteWhenFinished(true);
  934.     }
  935.     
  936.     return noErr;
  937. }
  938.  
  939.  
  940. // ---------------------------------------------------------------------------
  941. //        • ObeyCommand
  942. // ---------------------------------------------------------------------------
  943. //    Handle a command
  944.  
  945. Boolean
  946. LWindow::ObeyCommand(
  947.     CommandT    inCommand,
  948.     void        *ioParam)
  949. {
  950.     Boolean        cmdHandled = true;
  951.     
  952.     switch (inCommand) {
  953.         
  954.         case cmd_Close:
  955.             SendAEClose();
  956.             break;
  957.             
  958.         default:
  959.             cmdHandled = LCommander::ObeyCommand(inCommand, ioParam);
  960.             break;
  961.     }
  962.         
  963.     return cmdHandled;
  964. }
  965.  
  966.  
  967. // ---------------------------------------------------------------------------
  968. //        • FindCommandStatus
  969. // ---------------------------------------------------------------------------
  970. //    Return whether a Command is enabled and/or marked (in a Menu)
  971.  
  972. void
  973. LWindow::FindCommandStatus(
  974.     CommandT    inCommand,
  975.     Boolean        &outEnabled,
  976.     Boolean        &outUsesMark,
  977.     Char16        &outMark)
  978. {
  979.     switch (inCommand) {
  980.     
  981.         case cmd_Close:
  982.             outEnabled = true;
  983.             outUsesMark = false;
  984.             break;
  985.             
  986.         default:
  987.             LCommander::FindCommandStatus(inCommand, outEnabled,
  988.                                     outUsesMark, outMark);
  989.             break;
  990.     }
  991. }
  992.  
  993.  
  994. // ===========================================================================
  995. // • AppleEvent Object Model Support         AppleEvent Object Model Support •
  996. // ===========================================================================
  997.  
  998.  
  999. DescType
  1000. LWindow::GetModelKind() const
  1001. {
  1002.     return cWindow;
  1003. }
  1004.  
  1005.  
  1006. void
  1007. LWindow::MakeSelfSpecifier(
  1008.     AEDesc    &inSuperSpecifier,
  1009.     AEDesc    &outSelfSpecifier) const
  1010. {
  1011.     AEDesc    keyData;
  1012.     Int16    windowIndex = FindWindowIndex(mMacWindowP);
  1013.     OSErr    err = CreateOffsetDescriptor(windowIndex, &keyData);
  1014.     if (err != noErr) Throw_(err);
  1015.     
  1016.     err = CreateObjSpecifier(cWindow, &inSuperSpecifier, formAbsolutePosition,
  1017.                                 &keyData, true, &outSelfSpecifier);
  1018.     if (err != noErr) Throw_(err);
  1019. }
  1020.  
  1021.  
  1022. LModelProperty*
  1023. LWindow::GetModelProperty(
  1024.     DescType    inProperty)
  1025. {
  1026.     LModelProperty    *theProperty = nil;
  1027.     
  1028.     switch (inProperty) {
  1029.     
  1030.         case pName:
  1031.         case pPosition:
  1032.         case pBounds:
  1033.         case pIsZoomed:
  1034.         case pHasCloseBox:
  1035.         case pHasTitleBar:
  1036.         case pIsFloating:
  1037.         case pIsModal:
  1038.         case pIsResizable:
  1039.         case pIsZoomable:
  1040.         case pVisible:
  1041.             theProperty = new LModelProperty(inProperty, this);
  1042.             break;
  1043.             
  1044.         default:
  1045.             theProperty = LModelObject::GetModelProperty(inProperty);
  1046.     }
  1047.     
  1048.     return theProperty;
  1049. }
  1050.  
  1051.  
  1052. void
  1053. LWindow::GetAEProperty(
  1054.     DescType        inProperty,
  1055.     const AEDesc    &inRequestedType,
  1056.     AEDesc            &outPropertyDesc) const
  1057. {
  1058.     OSErr    err;
  1059.  
  1060.     switch (inProperty) {
  1061.     
  1062.         case pName:                    // Window Title
  1063.             Str255    theName;
  1064.             GetDescriptor(theName);
  1065.             err = AECreateDesc(typeChar, (Ptr) theName + 1,
  1066.                                 Length(theName), &outPropertyDesc);
  1067.             break;
  1068.     
  1069.         case pPosition:                // Top left of Frame in Global coords
  1070.             Point    thePosition = {0, 0};
  1071.             PortToGlobalPoint(thePosition);
  1072.             err = AECreateDesc(typeQDPoint, (Ptr) &thePosition,
  1073.                                 sizeof(Point), &outPropertyDesc);
  1074.             break;
  1075.             
  1076.         case pBounds:                // Frame in Global coords
  1077.             Rect    theBounds;
  1078.             CalcPortFrameRect(theBounds);
  1079.             PortToGlobalPoint(topLeft(theBounds));
  1080.             PortToGlobalPoint(botRight(theBounds));
  1081.             err = AECreateDesc(typeQDRectangle, (Ptr) &theBounds,
  1082.                                 sizeof(Rect), &outPropertyDesc);
  1083.             break;
  1084.             
  1085.         case pIsZoomed:                // Is Window at Standard state?
  1086.             Rect    stdBounds;
  1087.             Boolean    isZoomed = CalcStandardBounds(stdBounds);
  1088.             err = AECreateDesc(typeBoolean, (Ptr) &isZoomed,
  1089.                                 sizeof(Boolean), &outPropertyDesc);
  1090.             break;
  1091.         
  1092.         case pHasCloseBox:
  1093.             GetAEWindowAttribute(windAttr_CloseBox, outPropertyDesc);
  1094.             break;
  1095.             
  1096.         case pHasTitleBar:
  1097.             GetAEWindowAttribute(windAttr_TitleBar, outPropertyDesc);
  1098.             break;
  1099.             
  1100.         case pIsFloating:
  1101.             GetAEWindowAttribute(windAttr_Floating, outPropertyDesc);
  1102.             break;
  1103.             
  1104.         case pIsModal:
  1105.             GetAEWindowAttribute(windAttr_Modal, outPropertyDesc);
  1106.             break;
  1107.             
  1108.         case pIsResizable:
  1109.             GetAEWindowAttribute(windAttr_Resizable, outPropertyDesc);
  1110.             break;
  1111.             
  1112.         case pIsZoomable:            // Can Window be zoomed?
  1113.             GetAEWindowAttribute(windAttr_Zoomable, outPropertyDesc);
  1114.             break;
  1115.             
  1116.         case pVisible:
  1117.             Boolean    isVis = IsVisible();
  1118.             err = AECreateDesc(typeBoolean, (Ptr) &isVis,
  1119.                                 sizeof(Boolean), &outPropertyDesc);
  1120.             break;
  1121.             
  1122.         default:
  1123.             LModelObject::GetAEProperty(inProperty, inRequestedType,
  1124.                                             outPropertyDesc);
  1125.             break;
  1126.     }
  1127. }
  1128.  
  1129.  
  1130. void
  1131. LWindow::SetAEProperty(
  1132.     DescType        inProperty,
  1133.     const AEDesc    &inValue,
  1134.     AEDesc&            outAEReply)
  1135. {
  1136.     switch (inProperty) {
  1137.     
  1138.         case pName:
  1139.             Str255    theName;
  1140.             UExtractFromAEDesc::ThePString(inValue, theName);
  1141.             CheckThrow_
  1142.             SetDescriptor(theName);
  1143.             break;
  1144.     
  1145.         case pPosition:
  1146.             Point    thePosition;
  1147.             UExtractFromAEDesc::ThePoint(inValue, thePosition);
  1148.             CheckThrow_
  1149.             DoSetPosition(thePosition);
  1150.             break;
  1151.     
  1152.         case pBounds:
  1153.             Rect    theBounds;
  1154.             UExtractFromAEDesc::TheRect(inValue, theBounds);
  1155.             CheckThrow_
  1156.             DoSetBounds(theBounds);
  1157.             break;
  1158.             
  1159.         case pIsZoomed:
  1160.             Boolean    isZoomed;
  1161.             UExtractFromAEDesc::TheBoolean(inValue, isZoomed);
  1162.             CheckThrow_
  1163.             DoSetZoom(isZoomed);
  1164.             break;
  1165.             
  1166.         case pVisible:
  1167.             Boolean    makeVisible;
  1168.             UExtractFromAEDesc::TheBoolean(inValue, makeVisible);
  1169.             CheckThrow_
  1170.             if (makeVisible) {
  1171.                 Show();
  1172.             } else {
  1173.                 Hide();
  1174.             }
  1175.             break;
  1176.             
  1177.         default:
  1178.             LModelObject::SetAEProperty(inProperty, inValue, outAEReply);
  1179.             break;
  1180.     }
  1181. }
  1182.  
  1183.  
  1184. void
  1185. LWindow::GetAEWindowAttribute(
  1186.     Uint16    inAttribute,
  1187.     AEDesc    &outPropertyDesc) const
  1188. {
  1189.     Boolean    attrIsSet = HasAttribute(inAttribute);
  1190.     OSErr    err = AECreateDesc(typeBoolean, (Ptr) &attrIsSet,
  1191.                                 sizeof(Boolean), &outPropertyDesc);
  1192. }
  1193.  
  1194.  
  1195. void
  1196. LWindow::HandleAppleEvent(
  1197.     const AppleEvent&    inAppleEvent,
  1198.     AppleEvent&            outAEReply,
  1199.     long                inAENumber)
  1200. {
  1201.     switch (inAENumber) {
  1202.     
  1203.         case ae_Close:
  1204.             DoAEClose();
  1205.             break;
  1206.             
  1207.         default:
  1208.             LModelObject::HandleAppleEvent(inAppleEvent, outAEReply,
  1209.                                                 inAENumber);
  1210.             break;
  1211.     }
  1212. }
  1213.  
  1214.  
  1215. // ---------------------------------------------------------------------------
  1216. //        • DoSetPosition
  1217. // ---------------------------------------------------------------------------
  1218. //    Change the location of a Window
  1219. //
  1220. //    The top left corner of the Window's port rectangle is placed at
  1221. //    inPosition, which is in global coordinates
  1222.  
  1223. void
  1224. LWindow::DoSetPosition(
  1225.     Point    inPosition)                    // Top left in global coords
  1226. {
  1227.     MoveWindow(mMacWindowP, inPosition.h, inPosition.v, false);
  1228.  
  1229.     Point    offset = {0, 0};            // Moving Window changes the
  1230.     PortToGlobalPoint(offset);            //   UserBounds for zooming
  1231.     offset.h -= mUserBounds.left;
  1232.     offset.v -= mUserBounds.top;
  1233.     OffsetRect(&mUserBounds, offset.h, offset.v);
  1234.     mMoveOnlyUserZoom = false;
  1235. }
  1236.  
  1237.  
  1238. // ---------------------------------------------------------------------------
  1239. //        • CalcStandardBounds
  1240. // ---------------------------------------------------------------------------
  1241. //    Calculate the bounds of the Window at standard state and return whether
  1242. //    it is at standard state. The standard state depends on the screen
  1243. //    containing the largest area of the Window and the current standard size.
  1244. //
  1245. //    outStdBounds: Port rectangle of Window at standard size, global coords
  1246.  
  1247. Boolean
  1248. LWindow::CalcStandardBounds(
  1249.     Rect    &outStdBounds) const
  1250. {
  1251.                                     // Find GDevice containing largest
  1252.                                     //   portion of Window
  1253.     GDHandle    dominantDevice = UWindows::FindDominantDevice(
  1254.                             UWindows::GetWindowStructureRect(mMacWindowP));
  1255.     
  1256.                                     // Must compensate for MenuBar on the
  1257.                                     //   main screen
  1258.     Rect        screenRect = (**dominantDevice).gdRect;
  1259.     if (dominantDevice == ::GetMainDevice()) {
  1260.         screenRect.top += GetMBarHeight();
  1261.     }
  1262.     
  1263.     CalcStandardBoundsForScreen(screenRect, outStdBounds);
  1264.     
  1265.     return ::EqualRect(&outStdBounds,
  1266.                        &UWindows::GetWindowContentRect(mMacWindowP));
  1267. }
  1268.  
  1269.  
  1270. // ---------------------------------------------------------------------------
  1271. //        • CalcStandardBoundsForScreen
  1272. // ---------------------------------------------------------------------------
  1273. //    Calculate the bounds of the Window if it was at a Standard (zoomed out)
  1274. //    state on a Screen with the specified bounds.
  1275. //
  1276. //    inScreenBounds: Bounding box of screen in global coordinates
  1277. //    outStdBounds: Port rectangle of Window at standard size, global coords
  1278.  
  1279. void
  1280. LWindow::CalcStandardBoundsForScreen(
  1281.     const Rect    &inScreenBounds,
  1282.     Rect        &outStdBounds) const
  1283. {
  1284.                                     // Structure and Content regions are
  1285.                                     //   in global coordinates
  1286.     Rect    strucRect = UWindows::GetWindowStructureRect(mMacWindowP);
  1287.     Rect    contRect = UWindows::GetWindowContentRect(mMacWindowP);
  1288.     
  1289.                                     // Structure can be (and usually is)
  1290.                                     //   larger than Content
  1291.     Rect    border;
  1292.     border.left = contRect.left - strucRect.left;
  1293.     border.right = strucRect.right - contRect.right;
  1294.     border.top = contRect.top - strucRect.top;
  1295.     border.bottom = strucRect.bottom - contRect.bottom;
  1296.                          
  1297.                                      // Don't zoom too close to edge of screen
  1298.     Int16    screenWidth = inScreenBounds.right - inScreenBounds.left - 4;
  1299.     Int16    screenHeight = inScreenBounds.bottom - inScreenBounds.top - 4;
  1300.     
  1301.                                     // Standard dimensions are the minimum
  1302.                                     //   of mStandardSize and the size of
  1303.                                     //   the screen
  1304.     Int16    stdWidth = mStandardSize.width;
  1305.     if (stdWidth > screenWidth - (border.left + border.right)) {
  1306.         stdWidth = screenWidth - (border.left + border.right);
  1307.     }
  1308.     
  1309.     Int16    stdHeight = mStandardSize.height;
  1310.     if (stdHeight > screenHeight - (border.top + border.bottom)) {
  1311.         stdHeight = screenHeight - (border.top + border.bottom);
  1312.     }
  1313.  
  1314.                                     // Standard position is the point closest
  1315.                                     //   to the current position at which
  1316.                                     //   the Window will be all on screen
  1317.                                     
  1318.                                     // Move window horizontally so that left
  1319.                                     //   or right edge of Struction region is
  1320.                                     //   2 pixels from the edge of the screen
  1321.     Int16    stdLeft = contRect.left;
  1322.     if (stdLeft < inScreenBounds.left + border.left + 2) {
  1323.         stdLeft = inScreenBounds.left + border.left + 2;
  1324.     } else if (stdLeft > inScreenBounds.right - stdWidth - border.right - 2) {
  1325.         stdLeft = inScreenBounds.right - stdWidth - border.right - 2;
  1326.     }
  1327.     
  1328.                                     // Move window vertically so that top
  1329.                                     //   or bottom edge of Struction region is
  1330.                                     //   2 pixels from the edge of the screen
  1331.     Int16    stdTop = contRect.top;
  1332.     if (stdTop < inScreenBounds.top + border.top + 2) {
  1333.         stdTop = inScreenBounds.top + border.top + 2;
  1334.     } else if (stdTop > inScreenBounds.bottom - stdHeight - border.bottom - 2) {
  1335.         stdTop = inScreenBounds.bottom - stdHeight - border.bottom - 2;
  1336.     }
  1337.     
  1338.     outStdBounds.left = stdLeft;
  1339.     outStdBounds.right = stdLeft + stdWidth;
  1340.     outStdBounds.top = stdTop;
  1341.     outStdBounds.bottom = stdTop + stdHeight;
  1342. }
  1343.  
  1344.  
  1345. // ---------------------------------------------------------------------------
  1346. //        • DoSetZoom
  1347. // ---------------------------------------------------------------------------
  1348. //    Zoom window to either the Standard or User state
  1349.  
  1350. void
  1351. LWindow::DoSetZoom(
  1352.     Boolean    inZoomToStdState)
  1353. {
  1354.     if (!HasAttribute(windAttr_Zoomable)) {
  1355.         Throw_(errAENotModifiable);
  1356.     }
  1357.  
  1358.     Rect    currBounds = UWindows::GetWindowContentRect(mMacWindowP);
  1359.     Rect    zoomBounds;
  1360.  
  1361.     if (inZoomToStdState) {            // Zoom to Standard state
  1362.         if (CalcStandardBounds(zoomBounds)) {
  1363.             return;                    // Already at Standard state
  1364.         }
  1365.         
  1366.     } else {                        // Zoom to User state
  1367.         zoomBounds = mUserBounds;
  1368.         
  1369.         if (mMoveOnlyUserZoom) {    // Special case for zooming a Window
  1370.                                     //   that is at standard size, but
  1371.                                     //   is partially offscreen
  1372.             zoomBounds.right = zoomBounds.left +
  1373.                                 (currBounds.right - currBounds.left);
  1374.             zoomBounds.bottom = zoomBounds.top +
  1375.                                 (currBounds.bottom - currBounds.top);
  1376.         }
  1377.     }
  1378.     
  1379.     Int16    zoomWidth = zoomBounds.right - zoomBounds.left;
  1380.     Int16    zoomHeight = zoomBounds.bottom - zoomBounds.top;
  1381.     mMoveOnlyUserZoom = false;
  1382.     
  1383.         // To avoid unnecessary redraws, we check to see if the
  1384.         // current and zoom states are either the same size
  1385.         // or at the same location
  1386.         
  1387.     if ( ((currBounds.right - currBounds.left) == zoomWidth) &&
  1388.          ((currBounds.bottom - currBounds.top) == zoomHeight) ) {
  1389.                                     // Same size, just move
  1390.         MoveWindow(mMacWindowP, zoomBounds.left, zoomBounds.top, false);
  1391.         mMoveOnlyUserZoom = true;
  1392.     
  1393.     } else if (EqualPt(topLeft(currBounds), topLeft(zoomBounds))) {
  1394.                                     // Same location, just resize
  1395.         SizeWindow(mMacWindowP, zoomWidth, zoomHeight, false);
  1396.         ResizeFrameTo(zoomWidth, zoomHeight, true);
  1397.         
  1398.     } else {                        // Different size and location
  1399.                                     // Stuff zoom bounds into WindowRecord
  1400.                                     //   as standard state and zoom out
  1401.         WStateDataHandle    wStateH = (WStateDataHandle)
  1402.             ((WindowPeek) mMacWindowP)->dataHandle;
  1403.         (**wStateH).stdState = zoomBounds;
  1404.         FocusDraw();
  1405.         EraseRect(&mMacWindowP->portRect);
  1406.         ZoomWindow(mMacWindowP, inZoomOut, false);
  1407.         ResizeFrameTo(zoomWidth, zoomHeight, false);
  1408.     }
  1409. }
  1410.  
  1411.  
  1412. // ---------------------------------------------------------------------------
  1413. //        • DoSetBounds
  1414. // ---------------------------------------------------------------------------
  1415. //    Change size and location of a Window
  1416. //
  1417. //    inBounds, in global coords, specifies the new size and location of
  1418. //    the Window's port rectangle
  1419.  
  1420. void
  1421. LWindow::DoSetBounds(
  1422.     const Rect    &inBounds)            // Bounds in global coords
  1423. {
  1424.     SizeWindow(mMacWindowP, inBounds.right - inBounds.left,
  1425.                 inBounds.bottom - inBounds.top, false);
  1426.     MoveWindow(mMacWindowP, inBounds.left, inBounds.top, false);
  1427.     ResizeFrameTo(inBounds.right - inBounds.left,
  1428.                 inBounds.bottom - inBounds.top, true);
  1429.  
  1430.     SDimension16    frameSize;        // For Windows, Image is always the
  1431.     GetFrameSize(frameSize);        //   same size as its Frame
  1432.     ResizeImageTo(frameSize.width, frameSize.height, false);
  1433.     
  1434.                                     // Changing Bounds establishes a
  1435.                                     //   new User state for zooming
  1436.     CalcPortFrameRect(mUserBounds);
  1437.     PortToGlobalPoint(topLeft(mUserBounds));
  1438.     PortToGlobalPoint(botRight(mUserBounds));
  1439.     mMoveOnlyUserZoom = false;
  1440. }
  1441.  
  1442.  
  1443. // ===========================================================================
  1444. // • Static Member Functions                         Static Member Functions •
  1445. // ===========================================================================
  1446.  
  1447. // ---------------------------------------------------------------------------
  1448. //        • FindNthWindow
  1449. // ---------------------------------------------------------------------------
  1450. //    Return a WindowPtr to the Nth Window
  1451. //
  1452. //    Windows are ordered from front to back
  1453. //        For positive indexes, 1 is the front window, 2 is the second, etc.
  1454. //        For negative indexes, -1 is the last window, -2 next to last, etc.
  1455. //    If Abs(N) > number of windows or N = 0, return nil
  1456.  
  1457. WindowPtr
  1458. LWindow::FindNthWindow(
  1459.     Int16    inN)
  1460. {
  1461.     WindowPeek    theWindowP = nil;
  1462.     Int16        wIndex = inN;
  1463.     
  1464.     if (wIndex < 0) {                // Negative index counts from end
  1465.         Int16    windowCount = 0;    // Count how many windows there are
  1466.         theWindowP = LMGetWindowList();
  1467.         while (theWindowP) {
  1468.             windowCount++;
  1469.             theWindowP = theWindowP->nextWindow;
  1470.         }                            // Compute positive index
  1471.         wIndex = windowCount + wIndex + 1;
  1472.     }
  1473.     
  1474.     if (wIndex > 0) {                // Count down into linked list
  1475.         theWindowP = LMGetWindowList();
  1476.         while (--wIndex  && theWindowP) {
  1477.             theWindowP = theWindowP->nextWindow;
  1478.         }
  1479.     }
  1480.         
  1481.     return (WindowPtr) theWindowP;
  1482. }
  1483.  
  1484. // ---------------------------------------------------------------------------
  1485. //        • FindWindowIndex
  1486. // ---------------------------------------------------------------------------
  1487. //    Return index position of Window with the Application
  1488. //
  1489. //    Windows are ordered from front to back, with #1 being the front window.
  1490. //    If inWindowP is not found, returns 0;
  1491.  
  1492. Int16
  1493. LWindow::FindWindowIndex(
  1494.     WindowPtr    inWindowP)
  1495. {
  1496.     Int16        index = 1;
  1497.     WindowPeek    currWindowP = LMGetWindowList();
  1498.     
  1499.     while (currWindowP && (currWindowP != (WindowPeek) inWindowP)) {
  1500.         index++;
  1501.         currWindowP = currWindowP->nextWindow;
  1502.     }
  1503.     
  1504.     if (currWindowP == nil) {
  1505.         index = 0;
  1506.     }
  1507.     
  1508.     return index;
  1509. }
  1510.